﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Text;
using HiUpdateTools.Core;
using EnterpriseDT.Net.Ftp;
using System.Security.Cryptography.X509Certificates;
using System.Net.Cache;
using System.Threading.Tasks;

namespace HiUpdateTools.Client.Win
{
    public class WebDownload : WebClient
    {
        /// <summary>
        /// Time in milliseconds
        /// </summary>
        /// 
        public bool PassiveMode { get; set; }
        public int Timeout { get; set; }

        public WebDownload() : this(60000) { }

        public WebDownload(int timeout)
        {
            this.Timeout = timeout;
            RegisterFtps();
    
        }
        protected override void OnDownloadFileCompleted(System.ComponentModel.AsyncCompletedEventArgs e)
        {

            base.OnDownloadFileCompleted(e);
        }
        protected override void OnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
        {

            base.OnDownloadProgressChanged(e);
        }

        protected override WebRequest GetWebRequest(Uri address)
        {

            var request = base.GetWebRequest(address);
         
            return request;
        }
       
        public static void InitiateSSLTrust()
        {
            try
            {
                //Change SSL checks so that all checks pass
                ServicePointManager.ServerCertificateValidationCallback += BypassSslCertificateValidation;
                    
            }
            catch (Exception ex)
            {
               
            }
        }
        private static bool BypassSslCertificateValidation(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
        {
            return true;
        }
        private void RegisterFtps()
        {
            ///InitiateSSLTrust();
            WebRequest.RegisterPrefix("ftps", new FtpsWebRequestCreator(this));
            HttpRequestCachePolicy policy = new HttpRequestCachePolicy(HttpRequestCacheLevel.CacheIfAvailable);
            FtpWebRequest.DefaultCachePolicy = policy;
   
        }
        public class TrustAllCertsPolicy : ICertificatePolicy
        {
            public bool CheckValidationResult(
             ServicePoint srvPoint, X509Certificate certificate,
             WebRequest request, int certificateProblem)
            {
                return true;
            }
        }
        private sealed class FtpsWebRequestCreator : IWebRequestCreate
        {
            private WebDownload webDownload;

            public FtpsWebRequestCreator(WebDownload webDownload)
            {
                // TODO: Complete member initialization
                this.webDownload = webDownload;  
                InitiateSSLTrust();
           
            }
            public WebRequest Create(Uri uri)
            {
              FtpWebRequest webRequest = (FtpWebRequest)WebRequest.CreateDefault(new Uri(uri.AbsoluteUri.Remove(3, 1))); // Removes the "s" in "ftps://".
                webRequest.EnableSsl = true;
                webRequest.Credentials = new NetworkCredential("bonveris", "bisftp2011");
         

                ///webRequest.Credentials = this.webDownload.Credentials;
                webRequest.EnableSsl = true;
                webRequest.Method = WebRequestMethods.Ftp.DownloadFile;
                webRequest.UsePassive = true;
                webRequest.UseBinary = true;
                ///webRequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
              /// webRequest.CachePolicy.Level = System.Net.Cache.RequestCacheLevel.CacheIfAvailable;
                return webRequest;
            }
        }
        //public string DownloadFile()
    }

    public class UpdateChecker : IDisposable
    {

        private WebDownload _Downloader;
        private object _Lock = new object();
        public ClientConfig ClientConfg { get; set; }
        public ServerConfig ServerConfg { get; set; }
        public WebDownload Downloader
        {
            get
            {
                lock (_Lock)
                {
                    return _Downloader;
                }
            }
            set
            {
                lock (_Lock)
                {
                    _Downloader = value;
                }
            }
        }
        Version _ActualVersion;
        public void Dispose()
        {
            if (Downloader != null)
            {
                Downloader.Dispose();
                Downloader = null;
            }
        }
     

      
        public bool IsProcessOpen(string name)
        {
            foreach (Process clsProcess in Process.GetProcesses())
            {
                if (clsProcess.ProcessName == name)
                {
                    return true;
                }
            }
            return false;
        }
        private string _configPath;
        public WebDownload CreateDownloader()
        {

            var downloader = new WebDownload(15000);
            if (!ClientConfg.ClientAnonymous)
            {
                downloader.Credentials = new System.Net.NetworkCredential(ClientConfg.ClientUserName,
      Encoding.UTF8.GetString(Convert.FromBase64String(ClientConfg.ClientPassword)), "");
                ///wc.UseDefaultCredentials = false;


            }
         
            return downloader;

        }
        public UpdateChecker(string configPath, Version actualVersion)
        {
            _configPath = configPath;
         
            if (!File.Exists(configPath))
                throw new ArgumentException("Config file is not exist.");
            ClientConfg = ClientConfig.Load(configPath, typeof(ClientConfig)) as ClientConfig;
            if (ClientConfg == null)
                throw new ArgumentException("Config  is not loaded.");
            Downloader = CreateDownloader();

            _ActualVersion = actualVersion;


        }
        private FTPClient _ftpClient;
        public void ResetFtp() {

            _ftpClient = null;
        }
        private void InitFtpClient(Uri uri)
        {
            if (_ftpClient == null)
            {
                _ftpClient = new FTPClient();
                _ftpClient.RemoteHost = uri.Host;
                _ftpClient.ConnectMode = ClientConfg.PassiveMode ? FTPConnectMode.PASV : FTPConnectMode.ACTIVE;
                

                _ftpClient.Connect();
                if (!ClientConfg.ClientAnonymous)
                {
                    _ftpClient.User(ClientConfg.ClientUserName);
                    _ftpClient.Password(Encoding.UTF8.GetString(Convert.FromBase64String(ClientConfg.ClientPassword)));
                }
                _ftpClient.AutoPassiveIPSubstitution = false;
                _ftpClient.TransferType = FTPTransferType.BINARY;



            }
        }
        public byte[] DownloadData(Uri uri)
        {

         
                if (ClientConfg.ClientPathType == PathType.ftp)
                {

                    InitFtpClient(uri);

                    return _ftpClient.Get(uri.AbsolutePath);




                }
                else
                {

                    return Downloader.DownloadData(uri);
                }
           

        }
        public bool Check()
        {

            Uri newUri = new Uri(ClientConfg.ClientPathType.ToString() + "://" + ClientConfg.ClientPath.TrimEnd("/".ToCharArray()) + "/ServerConfig.xml");
            byte[] serverByte = DownloadData(newUri);
            ServerConfg = ServerConfig.Load(new MemoryStream(serverByte), typeof(ServerConfig)) as ServerConfig;
            if (string.IsNullOrEmpty(ClientConfg.Name))
            {
                ClientConfg.Name = ServerConfg.Name;
                ClientConfg.Save(_configPath);
            }
            if (new Version(ServerConfg.Version) > _ActualVersion)
            {
                return true;
            }

            return false;
        }



        public void RunUpdate()
        {
            Process.Start("HiUpdateTools.Client.Win.exe", "" + _configPath + " " + _ActualVersion.ToString());

        }

        internal void RunApplication()
        {
            string name = string.IsNullOrEmpty(ClientConfg.Name) ? ServerConfg.Name : ClientConfg.Name;
            Process.Start(name + ".exe", "/noupdate");

        }

        public Stream DownloadDataStream(Uri uri)
        {
            MemoryStream str = new MemoryStream();
            if (ClientConfg.ClientPathType == PathType.ftp || ClientConfg.ClientPathType == PathType.ftps)
            {
                InitFtpClient(uri);
              
                _ftpClient.Get(str, uri.AbsolutePath);
             
                 return str;




            }
            else
            {

                return Downloader.OpenRead(uri);
            }
        }
    }
}
